using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using MoreGen.Util;
using System.Xml.Serialization;

namespace MoreGen.MapTypes
{
    public class TableMap
    {
        internal static TableMap CurrentSerial;
        private TableMap()
        {
            CurrentSerial = this;
            _Project = Project.CurrentSerial;
        }
        public TableMap(Project p)
        {
            _Project = p;
        }

        private Project _Project;
        [XmlIgnore()]
        public Project Project
        {
            get { return _Project; }
        }

        private SerialDictionary<string, ColumnMap> _Columns = new SerialDictionary<string, ColumnMap>();
        [Browsable(false)]
        public SerialDictionary<string, ColumnMap> Columns
        {
            get { return _Columns; }
            set { _Columns = value; }
        }
        private string _TableName;
        [Category("Database")]
        public string TableName
        {
            get { return _TableName; }
            set 
            { 
                _TableName = value;
                _ClassName = GetSingleName();
            }
        }
        private string _ClassName;
        public string ClassName
        {
            get { return _ClassName; }
            set { _ClassName = value; }
        }

        private string _EnumName;
        public string EnumName
        {
            get { return _EnumName; }
            set { _EnumName = value; }
        }

        private string _EnumField;
        public string EnumField
        {
            get { return _EnumField; }
            set { _EnumField = value; }
        }
	
        private bool _ReadOnly;
        public bool ReadOnly
        {
            get { return _ReadOnly; }
            set { _ReadOnly = value; }
        }

        private bool _IsView;
        public bool IsView
        {
            get { return _IsView; }
            set { _IsView = value; }
        }

        private bool _CreateClass = true;
        public bool CreateClass
        {
            get { return _CreateClass; }
            set { _CreateClass = value; }
        }
        private bool _CreateEnum = false;
        public bool CreateEnum
        {
            get { return _CreateEnum; }
            set { _CreateEnum = value; }
        }

        private int _RowCount;
        public int RowCount
        {
            get { return _RowCount; }
            set { _RowCount = value; }
        }

        [XmlIgnore()]
        public string ClassFileName
        {
            get { return Project.SubDir + ClassName + ".cs"; }
        }

        [XmlIgnore()]
        public string XmlFileName
        {
            get { return Project.SubDir + ClassName + ".hbm.xml"; }
        }

        public override string ToString()
        {
            return ClassName;
        }

        internal bool HasCompositeKey()
        {
            int KeyCount = 0;

            foreach(ColumnMap col in Columns.Values)
            {
                if (col.IsPK)
                {
                    KeyCount++;
                    if (KeyCount > 1)
                        break;
                }
            }

            if (KeyCount > 1)
                return true;

            return false;
        }
        internal bool HasPrimaryKey()
        {
            foreach (ColumnMap col in Columns.Values)
            {
                if (col.IsPK)
                {
                    return true;
                }
            }

            return false;
        }

        internal ColumnMap PrimaryKey()
        {
            foreach (ColumnMap col in Columns.Values)
            {
                if (col.IsPK)
                {
                    return col;
                }
            }

            return null;
        }
        public bool CanCreateEnum()
        {
            // true if Primary key is one column & Integer and if rowcount<100 and at least one text column
            if (RowCount > 100)
                return false;
            if (HasCompositeKey())
                return false;

            bool FoundInt = false, FoundString = false;
            foreach (ColumnMap col in Columns.Values)
            {
                if (col.IsPK)
                {
                    if (col.DBType == "int")
                        FoundInt = true;
                }

                if (col.DBType == "char" || col.DBType == "nchar" || col.DBType == "varchar")
                    FoundString = true;
            }

            if (FoundInt && FoundString)
                return true;

            return false;  
        }

        private string FixCaseName()
        {
            if (!Project.Database.FixCase)
                return TableName;

            char[] t = TableName.ToLower().ToCharArray();

            for (int i = 0; i < t.Length; ++i)
            {
                if (t[i] == '_')
                {
                    if ((i + 1) < t.Length)
                        t[i + 1] = Char.ToUpper(t[i + 1]);
                    continue;
                }
                if (i == 0)
                    t[i] = char.ToUpper(t[0]);
            }

            return new String(t);
        }

        public string GetSingleName()
        {
            string fcn = FixCaseName();
            string t = TableName.ToLower();
            if (!t.EndsWith("s"))
            {
                // doesn't end with s
                return fcn;
            }

            if (t.EndsWith("ies"))
            {
                string EndChar = "y";

                // chop off and replace with a y
                if (TableName.EndsWith("S"))
                    EndChar = "Y";

                return fcn.Substring(0, fcn.Length - 3) + EndChar;
            }

            if (t.EndsWith("us") || t.EndsWith("ss"))   // eg bonus, address
                return fcn;

            // just chop off the s
            return fcn.Substring(0, fcn.Length - 1);
        }
        public string GetPluralName()
        {
            string fcn = FixCaseName();
            string t = TableName.ToLower();

            if (t.EndsWith("us") || t.EndsWith("ss"))   // eg bonus, address
                return fcn + "es";
            if (t.EndsWith("x") || t.EndsWith("z") || t.EndsWith("o"))   // eg box, buzz, potato
                return fcn + "es";
            if (t.EndsWith("sh") || t.EndsWith("ch"))   // eg watch, bush
                return fcn + "es";

            if (t.EndsWith("s"))
                return fcn;

            string EndChar;

            if (t.EndsWith("y") && !(t.EndsWith("ay") || t.EndsWith("ey") || t.EndsWith("iy") || t.EndsWith("oy") || t.EndsWith("uy")))
            {
                EndChar = "ies";
                return fcn.Substring(0, fcn.Length - 1) + EndChar;
            }

            if (t.EndsWith("f"))
            {
                EndChar = "ves";
                return fcn.Substring(0, fcn.Length - 1) + EndChar;
            }
            if (t.EndsWith("fe"))
            {
                EndChar = "ves";
                return fcn.Substring(0, fcn.Length - 2) + EndChar;
            }

            EndChar = "s";
            return fcn + EndChar;
        }
    }
}
